package controllers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import model.Pair;
import model.oanda.Instrument;
import model.oanda.Instruments;
import model.oanda.Order;
import model.oanda.Prices;
import model.oanda.Trades;
import play.Logger;
import play.libs.F.Function;
import play.libs.F.Function0;
import play.libs.F.Promise;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import ws.oanda.WsOanda;
import ws.sentiment.SentimentPair;
import ws.sentiment.WsSentiment;

//Promise;

public class Application extends Controller {

	private static List<Order> orders = new ArrayList<Order>();
	private static Map<String, Instrument> instruments = new HashMap<String, Instrument>();

	public static Promise<Result> index() {

		// WsSentiment.getPairs().parallelStream().map(SentimentPair::pair).filter(SentimentFilter::filter).count();

		Logger.debug("orders: " + orders);

//		orders.forEach(o -> {
//			WsOanda.cancelOrder(o).map(resp -> {
//				orders.remove(o);
//				return resp;
//			});
//		});

		final Promise<Trades> currentTrades=WsOanda.getTrades();
		final Promise<Map<String,Instrument>> instrumentsMap=getInstruments();
		final Promise<List<Pair>> pairs=WsSentiment.getLogin().map(WsSentiment::getPairs).map(SentimentPair::listPair);
		
		return currentTrades.flatMap(new Function<Trades, Promise<Result>>() {
			@Override
			public Promise<Result> apply(Trades pCurrentTrades) throws Throwable {
				
				pCurrentTrades.getTrades().forEach(ord->{
					
					final Promise<Prices> currentPrice=WsOanda.getPrice(ord.getInstrument());
					
					currentPrice.flatMap(price->{
						
						final Instrument inst=price.getPrices().get(0); 
						
						Logger.debug(String.format("Order id %s instrument %s -> old price: %f bid: %f ask: %f side: %s",ord.getId(),ord.getInstrument(),inst.getBid(),inst.getAsk(),ord.getPrice(),ord.getSide()));
						
						Float _1,_2;
						
						if(Order.BUY.equalsIgnoreCase(ord.getSide())){
							_1=inst.getBid();
							_2=ord.getPrice();
						}else{
							_1=ord.getPrice();
							_2=inst.getAsk();
						}
						
						float profitto=_1-_2;
						
						Logger.debug(String.format("Order %s -> profitto: %f",ord.getId(),profitto));
						
						if(profitto<0)
							return WsOanda.cancelOrder(ord);//.get(10, TimeUnit.SECONDS);
						
						return null;
					});
					
//					for(Order or: orders){
//						if(or.getTradeOpened().getId().equals(ord.getId())){
//							Logger.debug(String.format("Order %s -> old price: %f new price: %f side: %s",ord.getId(),or.getPrice(),ord.getPrice(),ord.getSide()));
//							
//							Order _1=null;
//							Order _2=null;
//							
//							if(Order.BUY.equalsIgnoreCase(ord.getSide())){
//								_1=or;
//								_2=ord;
//							}else{
//								_1=ord;
//								_2=or;
//							}
//							
//							float profitto=_1.getPrice()-_2.getPrice();
//							
//							Logger.debug(String.format("Order %s -> profitto: %f",ord.getId(),profitto));
//						}
//					}
					
					//WsOanda.cancelOrder(ord).get(10, TimeUnit.SECONDS);
				});
				
				return instrumentsMap.flatMap(new Function<Map<String,Instrument>,Promise<Result>>() {
					@Override
					public Promise<Result> apply(Map<String, Instrument> pInstrumentsMap) throws Throwable {
						return pairs.flatMap(new Function<List<Pair>, Promise<Result>>() {
							private Order order;

							@Override
							public Promise<Result> apply(List<Pair> pPairs)
									throws Throwable {
								
								pPairs.forEach(p -> {
									
									Optional<Instrument> instrument=Optional.ofNullable(pInstrumentsMap.get(p.name));
									
									if(instrument.isPresent()){							
										p.name = pInstrumentsMap.get(p.name).getInstrument();							
										order = new Order(p.name, 12l, p.side);							
										WsOanda.makeOrder(order).map(resp->{
											
											//Logger.debug("Order created");
											try{
												Order orderTmp=Json.fromJson(resp.asJson(), Order.class);
												if(orderTmp!=null && orderTmp.getTradeOpened()!=null){
													Logger.debug("Order id: "+orderTmp.getTradeOpened().getId());								
													orders.add(orderTmp);
												}else{
													Logger.debug(String.format("Impossible to make order for %s ",order.getInstrument()));
												}
											}catch(Exception e){
												e.printStackTrace();
											}
											return null;
										});
										
									}else{
										Logger.debug(String.format("Pair name: %s not found",p.name));
									}
//									.map(o->{
//										Logger.debug("Order id: "+o.getId());
//										return orders.add(o);});							
								});
								
								return Promise.promise(new Function0<Result>() {
									@Override
									public Result apply() throws Throwable {
										return TODO;
									}
								});						
							}
						});
					}
				});
			}
		});
		
		
		
		
//		
//		
//		init().map(new Function<Map<String, Instrument>, List<Pair>>() {
//
//			@Override
//			public List<Pair> apply(Map<String, Instrument> arg0)
//					throws Throwable {
//
//				List<Pair> result = .get(10, TimeUnit.SECONDS);
//
//				result.forEach(p -> {
//					p.name = arg0.get(p.name).getInstrument();
//				});
//
//				return result;
//			}
//		}).map(new Function<List<Pair>, Long>() {
//
//			@Override
//			public Long apply(List<Pair> list) throws Throwable {
//
//				return list
//						.stream()
//						.map(p -> {
//							return new Order(instruments.get(p.name)
//									.getInstrument(), 12l, p.side);
//						}).map(or -> {
//							
//							System.out.println(or);
//							
////							Promise<Order> po=WsOanda.makeOrder(or);
////							
////							
////							
////							return po.map(or1 -> {
////								orders.add(or1);
////								return or1;
////							});
//							return 1;
//						}).count();				
//			}
//		});
//
//		Logger.debug("******************");
//
//		// return ok(index.render("Your new application is ready."));
//		return badRequest("404");

	}

	public static Promise<Map<String, Instrument>> getInstruments() {

		if (instruments.size() == 0) {
			return WsOanda.getInstruments().map(resp -> {
				return Json.fromJson(resp.asJson(), Instruments.class);
			}).map(new Function<Instruments, Map<String, Instrument>>() {

				@Override
				public Map<String, Instrument> apply(Instruments arg0)
						throws Throwable {
					arg0.getInstruments().forEach(ins -> {
						instruments.put(ins.getDisplayName(), ins);
					});
					return instruments;
				}
			});
		} else {
			return Promise.promise(new Function0<Map<String, Instrument>>() {

				@Override
				public Map<String, Instrument> apply() throws Throwable {
					return instruments;
				}
			});
		}
	}

}
